//! Chinese Chess (Xiangqi) game engine for AI training
//! 
//! This library provides a complete implementation of Chinese Chess rules
//! and game mechanics, specifically designed for AI model training.

use std::fmt;
use serde::{Serialize, Deserialize};

pub mod board;
pub mod piece;
pub mod game;
pub mod moves;
pub mod utils;
pub mod ai;

/// Represents a position on the board using file (column) and rank (row)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Position {
    pub file: i8,  // 0-8 for files (columns)
    pub rank: i8,  // 0-9 for ranks (rows)
}

impl Position {
    /// Create a new position from file and rank
    pub fn new(file: i8, rank: i8) -> Option<Self> {
        if file >= 0 && file <= 8 && rank >= 0 && rank <= 9 {
            Some(Position { file, rank })
        } else {
            None
        }
    }

    /// Check if the position is within the board boundaries
    pub fn is_valid(&self) -> bool {
        self.file >= 0 && self.file <= 8 && self.rank >= 0 && self.rank <= 9
    }
}

/// Represents a side (Red or Black)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Side {
    Red,
    Black,
}

impl Side {
    /// Get the opposite side
    pub fn opposite(&self) -> Side {
        match self {
            Side::Red => Side::Black,
            Side::Black => Side::Red,
        }
    }
}

/// Represents the game result
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum GameResult {
    Win(Side),
    Draw,
    Ongoing,
}

/// Error types for the chess engine
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChessError {
    InvalidPosition,
    InvalidMove,
    WrongTurn,
    GameOver,
    IllegalMove(&'static str),
}

impl fmt::Display for ChessError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ChessError::InvalidPosition => write!(f, "Invalid position"),
            ChessError::InvalidMove => write!(f, "Invalid move"),
            ChessError::WrongTurn => write!(f, "Wrong turn"),
            ChessError::GameOver => write!(f, "Game is over"),
            ChessError::IllegalMove(reason) => write!(f, "Illegal move: {}", reason),
        }
    }
}

impl std::error::Error for ChessError {}

/// Result type for chess operations
pub type ChessResult<T> = Result<T, ChessError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_position_creation() {
        assert!(Position::new(0, 0).is_some());
        assert!(Position::new(8, 9).is_some());
        assert!(Position::new(-1, 0).is_none());
        assert!(Position::new(9, 0).is_none());
        assert!(Position::new(0, 10).is_none());
    }

    #[test]
    fn test_position_validity() {
        let valid_pos = Position { file: 0, rank: 0 };
        let invalid_pos = Position { file: 9, rank: 0 };
        assert!(valid_pos.is_valid());
        assert!(!invalid_pos.is_valid());
    }

    #[test]
    fn test_side_opposite() {
        assert_eq!(Side::Red.opposite(), Side::Black);
        assert_eq!(Side::Black.opposite(), Side::Red);
    }
}